package oo

import (
	"elegantGo/chapter17/controller/response"
	"elegantGo/chapter17/oo/primitive"
	"elegantGo/chapter17/oo/user"
	entuser "elegantGo/chapter17/repository/ent/user"
)

var UserFields = entuser.Columns

type UserVipResourceDiscounter interface {
	Discount() float64
}

type Users []User

type User interface {
	GetID() int
	SetID(id int)
	GetPhone() string
	SetPhone(v string)
	GetNickname() string
	SetNickname(v string)
	GetLevel() int
	SetLevel(v int)
	GetCategory() int
	SetCategory(v int)

	IsVip() bool
	IsAuthor(sessionUser User) bool
	IsAdministrator() bool
	Mapper() *response.User
}

func (oo Users) Mapper() response.Users {
	size := len(oo)
	respArticles := make(response.Users, size)
	for i := 0; i < size; i++ {
		respArticles[i] = oo[i].Mapper()
	}
	return respArticles
}

func NewUser(category int) User {
	var trait User
	switch category {
	case user.CategoryNormal:
		trait = &NormalUser{}
	case user.CategoryVipMonthly:
		trait = &VipMonthlyUser{}
	case user.CategoryVipYearly:
		trait = &VipYearlyUser{}
	case user.CategoryVipSuperYearlyUser:
		trait = &VipSuperYearlyUser{}
	case user.CategoryVipTwoYearlyUser:
		trait = &VipTwoYearlyUser{}
	}
	trait.SetCategory(category)

	return trait
}

type baseUser struct {
	id       primitive.ID
	phone    primitive.Phone
	nickname user.Nickname
	level    user.Level
	category user.Category
}

func (oo *baseUser) IsVip() bool {
	return oo.category.Value() > 0
}

func (oo *baseUser) IsAuthor(sessionUser User) bool {
	if sessionUser == nil {
		return false
	}

	return sessionUser.GetID() == oo.id.Value()
}

func (oo *baseUser) IsAdministrator() bool {
	return false
}

func (oo *baseUser) GetID() int {
	return oo.id.Value()
}

func (oo *baseUser) SetID(v int) {
	oo.id.SetValue(v)
}

func (oo *baseUser) GetPhone() string {
	return oo.phone.Value()
}

func (oo *baseUser) SetPhone(v string) {
	oo.phone.SetValue(v)
}

func (oo *baseUser) GetNickname() string {
	return oo.nickname.Value()
}

func (oo *baseUser) SetNickname(v string) {
	oo.nickname.SetValue(v)
}

func (oo *baseUser) GetLevel() int {
	return oo.level.Value()
}

func (oo *baseUser) SetLevel(v int) {
	oo.level.SetValue(v)
}

func (oo *baseUser) GetCategory() int {
	return oo.category.Value()
}

func (oo *baseUser) SetCategory(v int) {
	oo.category.SetValue(v)
}

func (oo *baseUser) Mapper() *response.User {
	if oo == nil {
		return nil
	}

	respUser := new(response.User)
	respUser.ID = oo.id.Value()
	respUser.Nickname = oo.nickname.Value()
	respUser.Level = oo.level.Value()
	respUser.Category = oo.category.Value()
	return respUser
}
